# Copyright (c) 2025 SenseTime. All Rights Reserved.
# Author: LazyLLM Team,  https://github.com/LazyAGI/LazyLLM
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
数据库迁移: init migrate

==========================================
自动生成的数据库迁移文件
==========================================

迁移信息:
---------
- 修订版本: 36622943e974
- 基于版本: 
- 创建时间: 2025-09-02 14:41:20.141037
- 迁移描述: init migrate

重要说明:
---------
⚠️  在生产环境执行前，请务必：
   1. 在测试环境中完整验证所有迁移操作
   2. 备份生产数据库
   3. 确认迁移操作的可逆性
   4. 评估大表操作的性能影响
   5. 准备回滚计划

📋 使用方法:
   - 升级到此版本: flask db upgrade
   - 降级到上一版本: flask db downgrade
   - 查看当前版本: flask db current
   - 查看迁移历史: flask db history

🔍 如有疑问，请联系数据库管理员或开发团队。
"""

# =============================================================================
# 导入必要的模块
# =============================================================================

from alembic import op
import sqlalchemy as sa
from models import StringUUID

# 导入其他必要的模块（由 Alembic 自动生成）
from sqlalchemy.dialects import mysql

# =============================================================================
# 迁移版本标识符
# =============================================================================

# 这些标识符由 Alembic 自动管理，请勿手动修改
revision = 'def28d16b22a'
down_revision = None
branch_labels = None
depends_on = None


# =============================================================================
# 数据库升级操作
# =============================================================================

def upgrade():
    """
    执行数据库升级操作。
    
    此函数包含将数据库从前一个版本升级到当前版本所需的所有操作。
    
    操作类型可能包括：
    - 创建新表 (op.create_table)
    - 删除表 (op.drop_table)
    - 添加列 (op.add_column)
    - 删除列 (op.drop_column)
    - 修改列 (op.alter_column)
    - 创建索引 (op.create_index)
    - 删除索引 (op.drop_index)
    - 创建外键约束 (op.create_foreign_key)
    - 删除外键约束 (op.drop_constraint)
    - 数据迁移操作
    
    ⚠️  安全提醒：
       - 大表操作可能需要较长时间，请在维护窗口内执行
       - 添加非空列时，确保已有数据的处理策略
       - 删除列或表前，确认数据已正确备份或迁移
       - 索引操作可能会锁定表，注意对业务的影响
    
    📝 执行记录：
       所有操作都会记录在 alembic_version 表中，便于追踪迁移历史。
    """
    # =========================================================================
    # 在此处添加升级操作
    # =========================================================================
    
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('account_integrates',
    sa.Column('id', StringUUID(), nullable=False),
    sa.Column('account_id', StringUUID(), nullable=False),
    sa.Column('provider', sa.String(length=16), nullable=False),
    sa.Column('open_id', sa.String(length=255), nullable=False),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.PrimaryKeyConstraint('id', name='account_integrate_pkey'),
    sa.UniqueConstraint('account_id', 'provider', name='unique_account_provider'),
    sa.UniqueConstraint('provider', 'open_id', name='unique_provider_open_id')
    )
    op.create_table('accounts',
    sa.Column('id', StringUUID(), nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('email', sa.String(length=255), nullable=False),
    sa.Column('phone', sa.String(length=255), nullable=True),
    sa.Column('password', sa.String(length=255), nullable=True),
    sa.Column('password_salt', sa.String(length=255), nullable=True),
    sa.Column('avatar', sa.String(length=255), nullable=True),
    sa.Column('interface_language', sa.String(length=255), nullable=True),
    sa.Column('timezone', sa.String(length=255), nullable=True),
    sa.Column('last_login_at', sa.DateTime(), nullable=True),
    sa.Column('last_login_ip', sa.String(length=255), nullable=True),
    sa.Column('last_active_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('status', sa.String(length=16), server_default=sa.text("'active'"), nullable=False),
    sa.Column('initialized_at', sa.DateTime(), nullable=True),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.PrimaryKeyConstraint('id', name='account_pkey')
    )
    with op.batch_alter_table('accounts', schema=None) as batch_op:
        batch_op.create_index('account_email_idx', ['email'], unique=False)
        batch_op.create_index('account_name_idx', ['name'], unique=False)
        batch_op.create_index('account_phone_idx', ['phone'], unique=False)

    op.create_table('api_key',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('user_id', sa.String(length=50), nullable=False),
    sa.Column('user_name', sa.String(length=50), nullable=True),
    sa.Column('tenant_id', sa.Text(), nullable=True),
    sa.Column('api_key', sa.String(length=40), nullable=False),
    sa.Column('description', sa.Text(), nullable=True),
    sa.Column('status', sa.String(length=10), server_default=sa.text("'active'"), nullable=False),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('expire_date', sa.Date(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.PrimaryKeyConstraint('id', name=op.f('api_key_pkey')),
    sa.UniqueConstraint('api_key', name=op.f('api_key_api_key_key'))
    )
    op.create_table('app_statistics',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('app_id', sa.String(length=36), nullable=False),
    sa.Column('call_type', sa.String(length=30), nullable=False),
    sa.Column('stat_date', sa.Date(), nullable=False),
    sa.Column('system_user_count', sa.Integer(), nullable=True),
    sa.Column('web_user_count', sa.Integer(), nullable=True),
    sa.Column('system_user_session_count', sa.Integer(), nullable=True),
    sa.Column('web_user_session_count', sa.Integer(), nullable=True),
    sa.Column('system_user_token_sum', sa.Integer(), nullable=True),
    sa.Column('web_user_token_sum', sa.Integer(), nullable=True),
    sa.Column('system_user_interaction_count', sa.Integer(), nullable=True),
    sa.Column('web_user_interaction_count', sa.Integer(), nullable=True),
    sa.Column('cost_time_p50', sa.Numeric(precision=10, scale=5), nullable=True),
    sa.Column('cost_time_p99', sa.Numeric(precision=10, scale=5), nullable=True),
    sa.Column('web_user_avg_interaction', sa.Float(), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=True),
    sa.PrimaryKeyConstraint('id', name=op.f('app_statistics_pkey'))
    )
    with op.batch_alter_table('app_statistics', schema=None) as batch_op:
        batch_op.create_index(batch_op.f('app_statistics_app_id_idx'), ['app_id'], unique=False)
        batch_op.create_index(batch_op.f('app_statistics_stat_date_idx'), ['stat_date'], unique=False)

    op.create_table('app_templates',
    sa.Column('id', StringUUID(), nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('description', sa.Text(), nullable=False),
    sa.Column('categories', sa.String(length=255), nullable=True),
    sa.Column('icon', sa.String(length=255), nullable=True),
    sa.Column('icon_background', sa.String(length=255), nullable=True),
    sa.Column('workflow_id', StringUUID(), nullable=True),
    sa.Column('status', sa.String(length=255), server_default=sa.text("'normal'"), nullable=False),
    sa.Column('enable_site', sa.Boolean(), server_default=sa.text('0'), nullable=False),
    sa.Column('enable_api', sa.Boolean(), server_default=sa.text('0'), nullable=False),
    sa.Column('is_public', sa.Boolean(), server_default=sa.text('0'), nullable=False),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('created_by', StringUUID(), nullable=True),
    sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('enable_backflow', sa.Boolean(), nullable=True),
    sa.PrimaryKeyConstraint('id', name='app_template_pkey')
    )
    with op.batch_alter_table('app_templates', schema=None) as batch_op:
        batch_op.create_index('app_template_id_idx', ['tenant_id'], unique=False)

    op.create_table('app_versions',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('app_id', StringUUID(), nullable=False),
    sa.Column('publisher', StringUUID(), nullable=False),
    sa.Column('release_time', sa.DateTime(), nullable=False),
    sa.Column('version', sa.String(length=255), nullable=False),
    sa.Column('description', sa.String(length=255), nullable=True),
    sa.Column('file_path', sa.String(length=255), nullable=False),
    sa.Column('status', sa.Boolean(), nullable=True),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=True),
    sa.PrimaryKeyConstraint('id', name='appversions_pkey')
    )
    with op.batch_alter_table('app_versions', schema=None) as batch_op:
        batch_op.create_index('appversions_app_id_idx', ['app_id'], unique=False)

    op.create_table('choice_tags',
    sa.Column('id', StringUUID(), nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.Column('type', sa.String(length=16), nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.PrimaryKeyConstraint('id', name='choice_tag_pkey')
    )
    with op.batch_alter_table('choice_tags', schema=None) as batch_op:
        batch_op.create_index('choice_tag_name_idx', ['name'], unique=False)
        batch_op.create_index('choice_tag_type_idx', ['type'], unique=False)

    op.create_table('conversation',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('app_id', sa.String(length=40), nullable=True),
    sa.Column('sessionid', sa.String(length=40), nullable=True),
    sa.Column('content', sa.Text(), nullable=True),
    sa.Column('files', sa.String(length=1024), nullable=True),
    sa.Column('from_who', sa.String(length=40), nullable=True),
    sa.Column('turn_number', sa.Integer(), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('is_satisfied', sa.Boolean(), nullable=True),
    sa.Column('user_feedback', sa.String(length=2048), nullable=True),
    sa.PrimaryKeyConstraint('id', name='conversation_pkey')
    )
    op.create_table('cooperation',
    sa.Column('id', StringUUID(), nullable=False),
    sa.Column('target_type', sa.String(length=16), nullable=False),
    sa.Column('target_id', sa.String(length=40), nullable=False),
    sa.Column('enable', sa.Boolean(), nullable=False),
    sa.Column('accounts', sa.Text(), nullable=True),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.Column('created_by', StringUUID(), nullable=False),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.PrimaryKeyConstraint('id', name='cooperation_pkey')
    )
    with op.batch_alter_table('cooperation', schema=None) as batch_op:
        batch_op.create_index('cooperation_created_by_idx', ['created_by'], unique=False)
        batch_op.create_index('cooperation_tenant_id_idx', ['tenant_id'], unique=False)

    op.create_table('cost_audits',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('app_id', sa.String(length=36), nullable=True),
    sa.Column('task_id', sa.Integer(), nullable=True),
    sa.Column('tenant_id', sa.String(length=36), nullable=True),
    sa.Column('user_id', sa.String(length=255), nullable=True),
    sa.Column('session_id', sa.String(length=40), nullable=True),
    sa.Column('call_type', sa.String(length=30), nullable=False),
    sa.Column('token_num', sa.Integer(), nullable=False),
    sa.Column('cost_time', sa.Numeric(precision=10, scale=6), nullable=True, comment='思考时长'),
    sa.Column('created_at', sa.DateTime(), nullable=True),
    sa.Column('updated_at', sa.DateTime(), nullable=True),
    sa.PrimaryKeyConstraint('id', name=op.f('cost_audits_pkey'))
    )
    op.create_table('data_set',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('description', sa.Text(), nullable=True),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('last_sync_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('data_type', sa.String(length=255), nullable=False),
    sa.Column('upload_type', sa.String(length=255), nullable=False),
    sa.Column('data_format', sa.String(length=255), nullable=True),
    sa.Column('from_type', sa.String(length=255), nullable=False),
    sa.Column('file_urls', sa.JSON(), nullable=True),
    sa.Column('file_paths', sa.JSON(), nullable=True),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=True),
    sa.Column('user_name', sa.String(length=50), nullable=False),
    sa.Column('tags_num', sa.Integer(), server_default='0', nullable=False),
    sa.Column('branches_num', sa.Integer(), server_default='0', nullable=False),
    sa.Column('default_branches_num', sa.Integer(), server_default='0', nullable=False),
    sa.Column('default_tags_num', sa.Integer(), server_default='0', nullable=False),
    sa.Column('app_id', sa.String(length=255), nullable=True),
    sa.Column('node_id', sa.String(length=255), nullable=True),
    sa.Column('reflux_type', sa.String(length=255), nullable=True),
    sa.PrimaryKeyConstraint('id', name='data_set_pkey')
    )
    op.create_table('data_set_file',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('name', sa.Text(), nullable=False),
    sa.Column('path', sa.Text(), nullable=False),
    sa.Column('download_url', sa.Text(), nullable=True),
    sa.Column('status', sa.String(length=255), nullable=False),
    sa.Column('operation', sa.String(length=255), nullable=True),
    sa.Column('data_set_id', sa.Integer(), nullable=False),
    sa.Column('data_set_version_id', sa.Integer(), nullable=False),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('finished_at', sa.DateTime(), nullable=True),
    sa.Column('file_type', sa.String(length=255), nullable=False),
    sa.Column('error_msg', sa.Text(), nullable=True),
    sa.PrimaryKeyConstraint('id', name='data_set_file_pkey')
    )
    op.create_table('data_set_reflux_data',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('data_set_id', sa.Integer(), nullable=False),
    sa.Column('data_set_version_id', sa.Integer(), nullable=False),
    sa.Column('app_id', sa.String(length=255), nullable=False),
    sa.Column('app_name', sa.String(length=255), nullable=True),
    sa.Column('module_id', sa.String(length=255), nullable=True),
    sa.Column('module_name', sa.String(length=255), nullable=True),
    sa.Column('module_type', sa.String(length=255), nullable=True),
    sa.Column('output_time', sa.DateTime(), nullable=True),
    sa.Column('module_input', sa.Text(), nullable=True),
    sa.Column('module_output', sa.Text(), nullable=True),
    sa.Column('conversation_id', sa.String(length=255), nullable=True),
    sa.Column('turn_number', sa.Integer(), nullable=True),
    sa.Column('is_satisfied', sa.Boolean(), nullable=True),
    sa.Column('user_feedback', sa.Text(), nullable=True),
    sa.Column('status', sa.String(length=255), nullable=True),
    sa.Column('operation', sa.String(length=255), nullable=True),
    sa.Column('finished_at', sa.DateTime(), nullable=True),
    sa.Column('error_msg', sa.Text(), nullable=True),
    sa.Column('user_id', sa.String(length=255), nullable=True),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('json_data', sa.JSON(), nullable=True),
    sa.PrimaryKeyConstraint('id', name='data_set_reflux_data_pkey')
    )
    op.create_table('data_set_version',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('version', sa.String(length=255), nullable=False),
    sa.Column('data_set_id', sa.Integer(), nullable=False),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('updated_at', sa.DateTime(), server_default=sa.text('now()'), nullable=False),
    sa.Column('status', sa.String(length=255), nullable=False),
    sa.Column('is_original', sa.Boolean(), nullable=False),
    sa.Column('data_set_file_ids', sa.JSON(), nullable=True),
    sa.Column('version_type', sa.String(length=255), nullable=False),
    sa.Column('previous_version_id', sa.Integer(), nullable=True),
    sa.Column('version_path', sa.String(length=255), nullable=True),
    sa.PrimaryKeyConstraint('id', name='data_set_version_pkey')
    )
    op.create_table('database_info',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.Column('created_by', StringUUID(), nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('database_name', sa.String(length=255), nullable=False),
    sa.Column('comment', sa.Text(), nullable=False),
    sa.Column('url', sa.String(length=255), nullable=True),
    sa.Column('type', sa.String(length=255), nullable=False),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.PrimaryKeyConstraint('id', name=op.f('database_info_pkey')),
    sa.UniqueConstraint('tenant_id', 'name', name='uq_database_info_name_tenant')
    )
    op.create_table('documents',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.Column('title', sa.String(length=255), nullable=False),
    sa.Column('index', sa.Integer(), nullable=False),
    sa.Column('doc_content', sa.Text(), nullable=False),
    sa.Column('status', sa.String(length=20), nullable=False),
    sa.Column('deleted_flag', sa.Integer(), nullable=False),
    sa.Column('created_by', StringUUID(), nullable=False),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.PrimaryKeyConstraint('id', name='doc_pkey')
    )
    op.create_table('evaluation_datasets_data',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('dataset_id', sa.Integer(), nullable=False),
    sa.Column('instruction', sa.Text(), nullable=False),
    sa.Column('output', sa.Text(), nullable=False),
    sa.Column('response', sa.Text(), nullable=True),
    sa.Column('is_evaluated', sa.Boolean(), nullable=True),
    sa.Column('option_select_id', sa.Integer(), nullable=True),
    sa.PrimaryKeyConstraint('id', name=op.f('evaluation_datasets_data_pkey'))
    )
    op.create_table('evaluation_datasets_file',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('name', sa.String(length=128), nullable=False),
    sa.Column('file_path', sa.String(length=256), nullable=False),
    sa.Column('has_response', sa.Boolean(), nullable=True),
    sa.Column('description', sa.Text(), nullable=True),
    sa.Column('size', sa.Integer(), nullable=True),
    sa.Column('uploaded_at', sa.DateTime(), nullable=True),
    sa.Column('file_type', sa.String(length=50), nullable=True),
    sa.PrimaryKeyConstraint('id', name=op.f('evaluation_datasets_file_pkey'))
    )
    op.create_table('evaluation_score',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('task_id', sa.Integer(), nullable=True),
    sa.Column('dimension_id', sa.Integer(), nullable=True),
    sa.Column('option_select_id', sa.Integer(), nullable=True),
    sa.Column('data_id', sa.Integer(), nullable=True),
    sa.Column('score', sa.Integer(), nullable=True),
    sa.Column('remark', sa.Text(), nullable=True),
    sa.Column('evaluated_at', sa.DateTime(), nullable=True),
    sa.PrimaryKeyConstraint('id', name=op.f('evaluation_score_pkey'))
    )
    op.create_table('evaluation_tasks',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('name', sa.String(length=30), nullable=False),
    sa.Column('model_type', sa.String(length=30), nullable=True),
    sa.Column('model_name', sa.String(length=255), nullable=True),
    sa.Column('evaluation_type', sa.String(length=20), nullable=False),
    sa.Column('dataset_id', sa.Integer(), nullable=False),
    sa.Column('evaluation_method', sa.String(length=20), nullable=False),
    sa.Column('failed_reason', sa.Text(), nullable=True),
    sa.Column('status', sa.String(length=40), nullable=True),
    sa.Column('prompt', sa.Text(), nullable=True),
    sa.Column('ai_evaluator_type', sa.String(length=30), nullable=True),
    sa.Column('ai_evaluator_name', sa.String(length=255), nullable=True),
    sa.Column('scene', sa.String(length=40), nullable=True),
    sa.Column('scene_descrp', sa.Text(), nullable=True),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.Column('tenant_id', sa.String(length=40), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=True),
    sa.PrimaryKeyConstraint('id', name=op.f('evaluation_tasks_pkey'))
    )
    op.create_table('file_record',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('size', sa.BigInteger(), nullable=False),
    sa.Column('file_path', sa.String(length=255), nullable=False),
    sa.Column('file_type', sa.String(length=50), nullable=False),
    sa.Column('file_md5', sa.String(length=255), nullable=False),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.Column('tenant_id', sa.String(length=50), nullable=True),
    sa.Column('storage_type', sa.String(length=50), nullable=False),
    sa.Column('knowledge_base_id', sa.String(length=50), nullable=False),
    sa.Column('used', sa.Boolean(), nullable=False),
    sa.Column('file_use_model', sa.String(length=50), nullable=False),
    sa.Column('model_id', sa.String(length=50), nullable=False),
    sa.Column('file_dir', sa.String(length=50), nullable=False),
    sa.PrimaryKeyConstraint('id', name='file_pkey')
    )
    op.create_table('finetune_custom_param',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('deleted_flag', sa.Integer(), nullable=False),
    sa.Column('created_by', StringUUID(), nullable=False),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('finetune_config', sa.Text(), nullable=False),
    sa.PrimaryKeyConstraint('id', name=op.f('finetune_custom_param_pkey'))
    )
    op.create_table('finetune_task',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('base_model', sa.Integer(), nullable=False),
    sa.Column('base_model_key', sa.String(length=255), nullable=False),
    sa.Column('base_model_key_ams', sa.String(length=255), nullable=True),
    sa.Column('target_model_name', sa.String(length=255), nullable=False),
    sa.Column('target_model_key', sa.String(length=255), nullable=False),
    sa.Column('target_model', sa.Integer(), nullable=True),
    sa.Column('created_from_info', sa.Text(), nullable=False),
    sa.Column('description', sa.Text(), nullable=False),
    sa.Column('status', sa.String(length=20), nullable=False),
    sa.Column('train_runtime', sa.Numeric(precision=20, scale=10), nullable=False),
    sa.Column('datasets', sa.Text(), nullable=False),
    sa.Column('deleted_flag', sa.Integer(), nullable=False),
    sa.Column('created_by', StringUUID(), nullable=False),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP(0)'), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.Column('is_online_model', sa.Boolean(), nullable=False),
    sa.Column('log_path', sa.String(length=255), nullable=False),
    sa.Column('finetune_config', sa.Text(), nullable=False),
    sa.Column('finetune_job_id', sa.String(length=100), nullable=False),
    sa.Column('finetuning_type', sa.String(length=20), nullable=False),
    sa.Column('train_end_time', sa.DateTime(), nullable=True),
    sa.Column('task_job_info', sa.String(length=500), nullable=True),
    sa.PrimaryKeyConstraint('id', name='finetune_pkey')
    )
    with op.batch_alter_table('finetune_task', schema=None) as batch_op:
        batch_op.create_index('finetune_task_deleted_flag_idx', ['deleted_flag'], unique=False)
        batch_op.create_index('finetune_task_tenant_id_idx', ['tenant_id'], unique=False)

    op.create_table('knowledge_base',
    sa.Column('id', StringUUID(), nullable=False),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.Column('user_name', sa.String(length=255), nullable=True),
    sa.Column('tenant_id', sa.String(length=50), nullable=True),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('description', sa.Text(), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.Column('path', sa.String(length=255), nullable=True),
    sa.PrimaryKeyConstraint('id', name='knowledge_base_pkey')
    )
    with op.batch_alter_table('knowledge_base', schema=None) as batch_op:
        batch_op.create_index('knowledge_base_user_idx', ['user_id'], unique=False)

    op.create_table('lazymodel_config_info',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('model_icon', sa.String(length=255), nullable=True),
    sa.Column('model_id', sa.Integer(), nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.Column('api_key', sa.String(length=255), nullable=False),
    sa.Column('proxy_url', sa.String(length=255), nullable=False),
    sa.Column('proxy_auth_info', sa.String(length=255), nullable=False),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.PrimaryKeyConstraint('id', name=op.f('lazymodel_config_info_pkey'))
    )
    op.create_table('lazymodel_online_models',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('model_id', sa.Integer(), nullable=False),
    sa.Column('model_name', sa.String(length=255), nullable=False),
    sa.Column('model_key', sa.String(length=255), nullable=False),
    sa.Column('can_finetune', sa.Integer(), nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.Column('parent_id', sa.Integer(), nullable=False),
    sa.Column('source_info', sa.String(length=255), nullable=True),
    sa.Column('is_finetune_model', sa.Boolean(), nullable=True),
    sa.Column('finetune_task_id', sa.Integer(), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.Column('deleted_flag', sa.Integer(), nullable=False),
    sa.Column('builtin_flag', sa.Boolean(), nullable=False),
    sa.PrimaryKeyConstraint('id', name=op.f('lazymodel_online_models_pkey'))
    )
    op.create_table('mcp_server',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('description', sa.Text(), nullable=True),
    sa.Column('icon', sa.String(length=255), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.Column('user_name', sa.String(length=255), nullable=True),
    sa.Column('tenant_id', StringUUID(), nullable=True),
    sa.Column('publish', sa.Boolean(), nullable=False),
    sa.Column('publish_at', sa.DateTime(), nullable=True),
    sa.Column('publish_type', sa.String(length=32), nullable=True),
    sa.Column('enable', sa.Boolean(), nullable=False),
    sa.Column('test_state', sa.String(length=50), nullable=True),
    sa.Column('transport_type', sa.String(length=50), nullable=False),
    sa.Column('timeout', sa.Integer(), nullable=True),
    sa.Column('stdio_command', sa.String(length=255), nullable=True),
    sa.Column('stdio_arguments', sa.Text(), nullable=True),
    sa.Column('stdio_env', mysql.JSON(), nullable=True),
    sa.Column('http_url', sa.Text(), nullable=True),
    sa.Column('headers', mysql.JSON(), nullable=True),
    sa.Column('sync_tools_at', sa.DateTime(), nullable=True),
    sa.PrimaryKeyConstraint('id', name='mcp_server_pkey')
    )
    op.create_table('mcp_tools',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('mcp_server_id', sa.Integer(), nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('description', sa.Text(), nullable=True),
    sa.Column('input_schema', mysql.JSON(), nullable=True),
    sa.Column('additional_properties', mysql.JSON(), nullable=True),
    sa.Column('annotations', mysql.JSON(), nullable=True),
    sa.Column('schema', sa.String(length=255), nullable=True),
    sa.Column('status', sa.String(length=50), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.PrimaryKeyConstraint('id', name='mcp_tools_pkey')
    )
    op.create_table('models_hub',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('model_icon', sa.String(length=255), nullable=False),
    sa.Column('model_type', sa.String(length=255), nullable=False),
    sa.Column('model_name', sa.String(length=255), nullable=False),
    sa.Column('description', sa.Text(), nullable=True),
    sa.Column('model_path', sa.String(length=255), nullable=False),
    sa.Column('model_from', sa.String(length=255), nullable=False),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=True),
    sa.Column('model_kind', sa.String(length=50), nullable=False),
    sa.Column('model_key', sa.String(length=255), nullable=False),
    sa.Column('model_key_ams', sa.String(length=255), nullable=True),
    sa.Column('access_tokens', sa.String(length=255), nullable=True),
    sa.Column('model_status', sa.Integer(), nullable=False),
    sa.Column('prompt_keys', sa.String(length=255), nullable=False),
    sa.Column('model_brand', sa.String(length=255), nullable=False),
    sa.Column('model_url', sa.String(length=255), nullable=False),
    sa.Column('model_dir', sa.String(length=255), nullable=False),
    sa.Column('download_message', sa.Text(), nullable=True),
    sa.Column('is_finetune_model', sa.Boolean(), nullable=True),
    sa.Column('can_finetune_model', sa.Boolean(), nullable=True),
    sa.Column('parent_model_id', sa.Integer(), nullable=True),
    sa.Column('source_info', sa.String(length=255), nullable=True),
    sa.Column('finetune_task_id', sa.Integer(), nullable=True),
    sa.Column('deleted_flag', sa.Integer(), nullable=False),
    sa.Column('builtin_flag', sa.Boolean(), nullable=False),
    sa.PrimaryKeyConstraint('id', name='models_pkey')
    )
    op.create_table('newapps',
    sa.Column('api_url', sa.String(length=255), nullable=True),
    sa.Column('enable_api_call', sa.String(length=10), server_default=sa.text("'0'"), nullable=True),
    sa.Column('id', StringUUID(), nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('description', sa.Text(), nullable=False),
    sa.Column('categories', sa.String(length=255), nullable=True),
    sa.Column('icon', sa.String(length=255), nullable=True),
    sa.Column('icon_background', sa.String(length=255), nullable=True),
    sa.Column('workflow_id', StringUUID(), nullable=True),
    sa.Column('status', sa.String(length=255), server_default=sa.text("'normal'"), nullable=False),
    sa.Column('enable_site', sa.Boolean(), server_default=sa.text('0'), nullable=False),
    sa.Column('enable_api', sa.Boolean(), server_default=sa.text('0'), nullable=False),
    sa.Column('is_public', sa.Boolean(), server_default=sa.text('0'), nullable=False),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('created_by', StringUUID(), nullable=True),
    sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('enable_backflow', sa.Boolean(), nullable=True),
    sa.PrimaryKeyConstraint('id', name='newapp_pkey')
    )
    with op.batch_alter_table('newapps', schema=None) as batch_op:
        batch_op.create_index('newapp_tenant_id_idx', ['tenant_id'], unique=False)

    op.create_table('newworkflows',
    sa.Column('id', StringUUID(), nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.Column('app_id', StringUUID(), nullable=False),
    sa.Column('type', sa.String(length=255), nullable=False),
    sa.Column('version', sa.String(length=255), nullable=False),
    sa.Column('graph', mysql.MEDIUMTEXT(), nullable=True),
    sa.Column('created_by', StringUUID(), nullable=False),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('updated_by', StringUUID(), nullable=True),
    sa.Column('updated_at', sa.DateTime(), nullable=True),
    sa.Column('publish_by', StringUUID(), nullable=True),
    sa.Column('publish_at', sa.DateTime(), nullable=True),
    sa.Column('main_app_id', StringUUID(), nullable=True),
    sa.Column('ref_app_ids', sa.String(length=1024), nullable=True),
    sa.Column('ref_tool_ids', sa.String(length=1024), nullable=True),
    sa.Column('ref_model_ids', sa.String(length=1024), nullable=True),
    sa.Column('ref_knowledge_ids', sa.String(length=1024), nullable=True),
    sa.PrimaryKeyConstraint('id', name='newworkflow_pkey')
    )
    with op.batch_alter_table('newworkflows', schema=None) as batch_op:
        batch_op.create_index('newworkflow_version_idx', ['tenant_id', 'app_id', 'version'], unique=False)

    op.create_table('operation_logs',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.Column('module', sa.String(length=100), nullable=False),
    sa.Column('action', sa.String(length=100), nullable=False),
    sa.Column('details', sa.Text(), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=True),
    sa.PrimaryKeyConstraint('id', name=op.f('operation_logs_pkey'))
    )
    op.create_table('prompts',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('user_id', sa.String(length=255), nullable=True),
    sa.Column('tenant_id', sa.String(length=36), nullable=True),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('describe', sa.String(length=1024), nullable=True),
    sa.Column('content', sa.Text(), nullable=False),
    sa.Column('category', sa.String(length=20), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=True),
    sa.Column('updated_at', sa.DateTime(), nullable=True),
    sa.PrimaryKeyConstraint('id', name=op.f('prompts_pkey'))
    )
    op.create_table('quota_requests',
    sa.Column('id', StringUUID(), nullable=False),
    sa.Column('request_type', sa.String(length=20), nullable=True, comment="'storage' or 'gpu'"),
    sa.Column('requested_amount', sa.Integer(), nullable=True, comment='申请配额(gpu单位张，存储单位GB)'),
    sa.Column('approved_amount', sa.Integer(), nullable=True, comment='批准配额(gpu单位张，存储单位GB)'),
    sa.Column('reason', sa.Text(), nullable=True, comment='申请理由'),
    sa.Column('tenant_id', StringUUID(), nullable=True, comment='工作区ID'),
    sa.Column('account_id', StringUUID(), nullable=True, comment='申请人ID'),
    sa.Column('status', sa.String(length=20), nullable=True, comment='状态：pending/approved/rejected/expired'),
    sa.Column('created_at', sa.DateTime(), nullable=True, comment='创建时间'),
    sa.Column('updated_at', sa.DateTime(), nullable=True, comment='更新时间'),
    sa.Column('processed_at', sa.DateTime(), nullable=True, comment='处理时间'),
    sa.Column('reject_reason', sa.Text(), nullable=True, comment='驳回理由'),
    sa.PrimaryKeyConstraint('id', name='quota_requests_pkey')
    )
    op.create_table('script_model',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('description', sa.Text(), nullable=True),
    sa.Column('icon', sa.String(length=255), nullable=False),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=True),
    sa.Column('user_name', sa.String(length=50), nullable=False),
    sa.Column('script_url', sa.String(length=255), nullable=False),
    sa.Column('script_type', sa.String(length=50), nullable=False),
    sa.Column('data_type', sa.String(length=50), nullable=False),
    sa.Column('upload_status', sa.String(length=50), nullable=False),
    sa.PrimaryKeyConstraint('id', name='script_model_pkey')
    )
    op.create_table('table_info',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.Column('created_by', StringUUID(), nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('database_id', sa.Integer(), nullable=False),
    sa.Column('comment', sa.Text(), nullable=False),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.PrimaryKeyConstraint('id', name=op.f('table_info_pkey'))
    )
    op.create_table('tag_bindings',
    sa.Column('id', StringUUID(), nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.Column('target_id', sa.String(length=40), nullable=False),
    sa.Column('type', sa.String(length=16), nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.PrimaryKeyConstraint('id', name='tag_binding_pkey')
    )
    with op.batch_alter_table('tag_bindings', schema=None) as batch_op:
        batch_op.create_index('tag_bind_target_id_idx', ['target_id'], unique=False)

    op.create_table('tags',
    sa.Column('id', StringUUID(), nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.Column('type', sa.String(length=16), nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.PrimaryKeyConstraint('id', name='tag_pkey')
    )
    with op.batch_alter_table('tags', schema=None) as batch_op:
        batch_op.create_index('tag_name_idx', ['name'], unique=False)
        batch_op.create_index('tag_type_idx', ['type'], unique=False)

    op.create_table('tenant_account_joins',
    sa.Column('id', StringUUID(), nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.Column('account_id', StringUUID(), nullable=False),
    sa.Column('current', sa.Boolean(), server_default=sa.text('0'), nullable=False),
    sa.Column('role', sa.String(length=16), server_default='normal', nullable=False),
    sa.Column('invited_by', StringUUID(), nullable=True),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.PrimaryKeyConstraint('id', name='tenant_account_join_pkey'),
    sa.UniqueConstraint('tenant_id', 'account_id', name='unique_tenant_account_join')
    )
    with op.batch_alter_table('tenant_account_joins', schema=None) as batch_op:
        batch_op.create_index('tenant_account_join_account_id_idx', ['account_id'], unique=False)
        batch_op.create_index('tenant_account_join_tenant_id_idx', ['tenant_id'], unique=False)

    op.create_table('tenants',
    sa.Column('id', StringUUID(), nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('encrypt_public_key', sa.Text(), nullable=True),
    sa.Column('plan', sa.String(length=255), server_default=sa.text("'basic'"), nullable=False),
    sa.Column('status', sa.String(length=255), server_default=sa.text("'normal'"), nullable=False),
    sa.Column('custom_config', sa.Text(), nullable=True),
    sa.Column('created_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('updated_at', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('storage_quota', sa.Integer(), server_default='0', nullable=False),
    sa.Column('storage_used_bytes', sa.BigInteger(), server_default='0', nullable=False),
    sa.Column('gpu_quota', sa.Integer(), server_default='0', nullable=False, comment='GPU算力配额(张)'),
    sa.Column('gpu_used', sa.Integer(), server_default='0', nullable=False, comment='已使用GPU算力(张)'),
    sa.Column('enable_ai', sa.Boolean(), nullable=False),
    sa.PrimaryKeyConstraint('id', name='tenant_pkey')
    )
    op.create_table('tool',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('description', sa.Text(), nullable=True),
    sa.Column('icon', sa.String(length=255), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.Column('user_name', sa.String(length=255), nullable=True),
    sa.Column('tenant_id', StringUUID(), nullable=True),
    sa.Column('tool_type', sa.String(length=50), nullable=False),
    sa.Column('tool_kind', sa.String(length=50), nullable=False),
    sa.Column('tool_mode', sa.String(length=50), nullable=False),
    sa.Column('tool_ide_code', sa.Text(), nullable=True),
    sa.Column('tool_ide_code_type', sa.String(length=50), nullable=True),
    sa.Column('tool_field_input_ids', mysql.JSON(), nullable=True),
    sa.Column('tool_field_output_ids', mysql.JSON(), nullable=True),
    sa.Column('tool_api_id', sa.Integer(), nullable=True),
    sa.Column('publish', sa.Boolean(), nullable=False),
    sa.Column('publish_at', sa.DateTime(), nullable=True),
    sa.Column('publish_type', sa.String(length=32), nullable=True),
    sa.Column('enable', sa.Boolean(), nullable=False),
    sa.Column('test_state', sa.String(length=50), nullable=True),
    sa.Column('is_draft', sa.Boolean(), nullable=True),
    sa.Column('tool_id', StringUUID(), nullable=True),
    sa.PrimaryKeyConstraint('id', name='tool_pkey')
    )
    op.create_table('tool_api',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('url', sa.Text(), nullable=False),
    sa.Column('header', mysql.JSON(), nullable=True),
    sa.Column('auth_method', sa.String(length=50), nullable=True),
    sa.Column('api_key', sa.Text(), nullable=True),
    sa.Column('request_type', sa.String(length=50), nullable=False),
    sa.Column('request_body', mysql.JSON(), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.Column('grant_type', sa.String(length=200), nullable=True),
    sa.Column('endpoint_url', sa.Text(), nullable=True),
    sa.Column('audience', sa.String(length=200), nullable=True),
    sa.Column('subject_token', sa.Text(), nullable=True),
    sa.Column('subject_token_type', sa.String(length=200), nullable=True),
    sa.Column('scope', sa.String(length=200), nullable=True),
    sa.Column('client_id', sa.String(length=50), nullable=True),
    sa.Column('client_secret', sa.String(length=50), nullable=True),
    sa.Column('client_url', sa.Text(), nullable=True),
    sa.Column('authorization_url', sa.Text(), nullable=True),
    sa.Column('authorization_content_type', sa.Text(), nullable=True),
    sa.PrimaryKeyConstraint('id', name='tool_api_pkey')
    )
    op.create_table('tool_auth',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('tool_id', sa.Integer(), nullable=True),
    sa.Column('tool_api_id', sa.Integer(), nullable=True),
    sa.Column('endpoint_url', sa.Text(), nullable=True),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.Column('user_name', sa.String(length=255), nullable=True),
    sa.Column('user_type', sa.String(length=50), nullable=True),
    sa.Column('location', sa.String(length=50), nullable=True),
    sa.Column('param_name', sa.String(length=255), nullable=True),
    sa.Column('token', sa.String(length=255), nullable=True),
    sa.Column('token_secret', sa.String(length=255), nullable=True),
    sa.Column('refresh_token', sa.String(length=255), nullable=True),
    sa.Column('id_token', sa.String(length=255), nullable=True),
    sa.Column('token_type', sa.String(length=255), nullable=True),
    sa.Column('is_share', sa.Boolean(), nullable=False),
    sa.Column('is_auth_success', sa.Boolean(), nullable=False),
    sa.Column('state', sa.String(length=255), nullable=True),
    sa.Column('client_id', sa.String(length=255), nullable=True),
    sa.Column('client_secret', sa.String(length=255), nullable=True),
    sa.Column('expires_at', sa.DateTime(), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.PrimaryKeyConstraint('id', name='tool_auth_pkey')
    )
    op.create_table('tool_field',
    sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
    sa.Column('name', sa.String(length=255), nullable=False),
    sa.Column('description', sa.Text(), nullable=False),
    sa.Column('field_type', sa.String(length=50), nullable=False),
    sa.Column('field_format', sa.String(length=50), nullable=False),
    sa.Column('file_field_format', sa.String(length=50), nullable=True),
    sa.Column('field_use_model', sa.String(length=50), nullable=True),
    sa.Column('required', sa.Boolean(), nullable=True),
    sa.Column('default_value', sa.String(length=255), nullable=True),
    sa.Column('created_at', sa.DateTime(), nullable=False),
    sa.Column('updated_at', sa.DateTime(), nullable=False),
    sa.Column('tool_id', sa.Integer(), nullable=True),
    sa.Column('visible', sa.Boolean(), nullable=False),
    sa.Column('user_id', sa.String(length=255), nullable=False),
    sa.PrimaryKeyConstraint('id', name='tool_field_pkey')
    )
    op.create_table('user_notifications',
    sa.Column('id', StringUUID(), nullable=False),
    sa.Column('module', sa.String(length=64), nullable=False, comment='消息所属模块'),
    sa.Column('source_id', sa.String(length=64), nullable=True, comment='来源id'),
    sa.Column('user_id', sa.String(length=36), nullable=True, comment='用户id'),
    sa.Column('user_body', sa.Text(), nullable=True, comment='用户回执消息体'),
    sa.Column('user_read', sa.Boolean(), nullable=True, comment='用户是否已读回执消息'),
    sa.Column('user_read_time', sa.DateTime(), nullable=True, comment='用户已读回执时间'),
    sa.Column('notify_user1_id', sa.String(length=36), nullable=True, comment='通知人1id'),
    sa.Column('notify_user1_body', sa.Text(), nullable=True, comment='通知人1消息体'),
    sa.Column('notify_user1_read', sa.Boolean(), nullable=True, comment='通知人1是否已读'),
    sa.Column('notify_user1_read_time', sa.DateTime(), nullable=True, comment='通知人1已读时间'),
    sa.Column('notify_user2_id', sa.String(length=36), nullable=True, comment='通知人2id'),
    sa.Column('notify_user2_body', sa.Text(), nullable=True, comment='通知人2消息体'),
    sa.Column('notify_user2_read', sa.Boolean(), nullable=True, comment='通知人2是否已读'),
    sa.Column('notify_user2_read_time', sa.DateTime(), nullable=True, comment='通知人2已读时间'),
    sa.Column('created_at', sa.DateTime(), nullable=True, comment='创建时间'),
    sa.PrimaryKeyConstraint('id', name='user_notifications_pkey')
    )
    op.create_table('workrefer',
    sa.Column('id', StringUUID(), nullable=False),
    sa.Column('app_id', StringUUID(), nullable=False),
    sa.Column('target_type', sa.String(length=16), nullable=False),
    sa.Column('target_id', sa.String(length=40), nullable=False),
    sa.PrimaryKeyConstraint('id', name='workrefer_pkey')
    )
    with op.batch_alter_table('workrefer', schema=None) as batch_op:
        batch_op.create_index('workrefer_app_idx', ['app_id'], unique=False)

    op.create_table('ai_tools',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('name', sa.String(length=50), nullable=False),
    sa.Column('content', sa.String(length=255), nullable=True),
    sa.Column('inferservice', sa.String(length=50), nullable=True),
    sa.Column('model_name', sa.String(length=50), nullable=False),
    sa.Column('tenant_id', StringUUID(), nullable=False),
    sa.ForeignKeyConstraint(['tenant_id'], ['tenants.id'], name=op.f('ai_tools_tenant_id_fkey')),
    sa.PrimaryKeyConstraint('id', 'tenant_id', name='ai_tools_pkey')
    )
    op.create_table('evaluation_dimensions',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('dimension_name', sa.String(length=30), nullable=False),
    sa.Column('dimension_description', sa.String(length=100), nullable=True),
    sa.Column('task_id', sa.Integer(), nullable=False),
    sa.Column('ai_base_score', sa.Integer(), nullable=True),
    sa.ForeignKeyConstraint(['task_id'], ['evaluation_tasks.id'], name=op.f('evaluation_dimensions_task_id_fkey')),
    sa.PrimaryKeyConstraint('id', name=op.f('evaluation_dimensions_pkey'))
    )
    op.create_table('infer_model_service_groups',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('tenant_id', sa.String(length=36), nullable=True),
    sa.Column('model_name', sa.String(length=100), nullable=False),
    sa.Column('model_type', sa.String(length=255), nullable=False),
    sa.Column('model_id', sa.Integer(), nullable=False),
    sa.Column('created_by', sa.String(length=36), nullable=False),
    sa.Column('created_time', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('updated_by', sa.String(length=36), nullable=False),
    sa.Column('updated_time', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.ForeignKeyConstraint(['model_id'], ['models_hub.id'], name=op.f('infer_model_service_groups_model_id_fkey')),
    sa.PrimaryKeyConstraint('id', name=op.f('infer_model_service_groups_pkey'))
    )
    op.create_table('dimension_options',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('option_description', sa.String(length=50), nullable=False),
    sa.Column('value', sa.Integer(), nullable=False),
    sa.Column('dimension_id', sa.Integer(), nullable=False),
    sa.ForeignKeyConstraint(['dimension_id'], ['evaluation_dimensions.id'], name=op.f('dimension_options_dimension_id_fkey')),
    sa.PrimaryKeyConstraint('id', name=op.f('dimension_options_pkey'))
    )
    op.create_table('infer_model_services',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('tenant_id', sa.String(length=36), nullable=True),
    sa.Column('group_id', sa.Integer(), nullable=False),
    sa.Column('job_id', sa.String(length=36), nullable=True),
    sa.Column('gid', sa.String(length=36), nullable=True),
    sa.Column('logs', sa.Text(), nullable=True),
    sa.Column('model_id', sa.Integer(), nullable=False),
    sa.Column('name', sa.String(length=100), nullable=False),
    sa.Column('created_by', sa.String(length=36), nullable=False),
    sa.Column('created_time', sa.DateTime(), server_default=sa.text('CURRENT_TIMESTAMP'), nullable=False),
    sa.Column('updated_by', sa.String(length=36), nullable=False),
    sa.Column('updated_time', sa.DateTime(), nullable=False),
    sa.ForeignKeyConstraint(['group_id'], ['infer_model_service_groups.id'], name=op.f('infer_model_services_group_id_fkey')),
    sa.ForeignKeyConstraint(['model_id'], ['models_hub.id'], name=op.f('infer_model_services_model_id_fkey')),
    sa.PrimaryKeyConstraint('id', name=op.f('infer_model_services_pkey'))
    )
    # ### end Alembic commands ###


# =============================================================================
# 数据库降级操作
# =============================================================================

def downgrade():
    """
    执行数据库降级操作。
    
    此函数包含将数据库从当前版本回滚到前一个版本所需的所有操作。
    这些操作应该能够完全撤销 upgrade() 函数中的所有变更。
    
    降级操作特点：
    - 必须与升级操作完全对应
    - 操作顺序通常与升级操作相反
    - 需要考虑数据丢失的风险
    
    ⚠️  重要警告：
       - 降级可能导致数据丢失，特别是删除列或表的操作
       - 某些操作可能不可逆，如数据类型转换
       - 执行前必须确保数据已备份
       - 不是所有迁移都支持安全的降级操作
    
    🔄 常见降级操作：
       - 如果升级时创建了表，降级时应删除表
       - 如果升级时添加了列，降级时应删除列
       - 如果升级时修改了列，降级时应恢复原始定义
       - 如果升级时创建了索引，降级时应删除索引
    
    💡 最佳实践：
       - 优先设计可逆的迁移操作
       - 对于不可逆操作，在注释中明确说明
       - 考虑使用数据迁移来保护重要数据
    """
    # =========================================================================
    # 在此处添加降级操作
    # =========================================================================
    
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_table('infer_model_services')
    op.drop_table('dimension_options')
    op.drop_table('infer_model_service_groups')
    op.drop_table('evaluation_dimensions')
    op.drop_table('ai_tools')
    with op.batch_alter_table('workrefer', schema=None) as batch_op:
        batch_op.drop_index('workrefer_app_idx')

    op.drop_table('workrefer')
    op.drop_table('user_notifications')
    op.drop_table('tool_field')
    op.drop_table('tool_auth')
    op.drop_table('tool_api')
    op.drop_table('tool')
    op.drop_table('tenants')
    with op.batch_alter_table('tenant_account_joins', schema=None) as batch_op:
        batch_op.drop_index('tenant_account_join_tenant_id_idx')
        batch_op.drop_index('tenant_account_join_account_id_idx')

    op.drop_table('tenant_account_joins')
    with op.batch_alter_table('tags', schema=None) as batch_op:
        batch_op.drop_index('tag_type_idx')
        batch_op.drop_index('tag_name_idx')

    op.drop_table('tags')
    with op.batch_alter_table('tag_bindings', schema=None) as batch_op:
        batch_op.drop_index('tag_bind_target_id_idx')

    op.drop_table('tag_bindings')
    op.drop_table('table_info')
    op.drop_table('script_model')
    op.drop_table('quota_requests')
    op.drop_table('prompts')
    op.drop_table('operation_logs')
    with op.batch_alter_table('newworkflows', schema=None) as batch_op:
        batch_op.drop_index('newworkflow_version_idx')

    op.drop_table('newworkflows')
    with op.batch_alter_table('newapps', schema=None) as batch_op:
        batch_op.drop_index('newapp_tenant_id_idx')

    op.drop_table('newapps')
    op.drop_table('models_hub')
    op.drop_table('mcp_tools')
    op.drop_table('mcp_server')
    op.drop_table('lazymodel_online_models')
    op.drop_table('lazymodel_config_info')
    with op.batch_alter_table('knowledge_base', schema=None) as batch_op:
        batch_op.drop_index('knowledge_base_user_idx')

    op.drop_table('knowledge_base')
    with op.batch_alter_table('finetune_task', schema=None) as batch_op:
        batch_op.drop_index('finetune_task_tenant_id_idx')
        batch_op.drop_index('finetune_task_deleted_flag_idx')

    op.drop_table('finetune_task')
    op.drop_table('finetune_custom_param')
    op.drop_table('file_record')
    op.drop_table('evaluation_tasks')
    op.drop_table('evaluation_score')
    op.drop_table('evaluation_datasets_file')
    op.drop_table('evaluation_datasets_data')
    op.drop_table('documents')
    op.drop_table('database_info')
    op.drop_table('data_set_version')
    op.drop_table('data_set_reflux_data')
    op.drop_table('data_set_file')
    op.drop_table('data_set')
    op.drop_table('cost_audits')
    with op.batch_alter_table('cooperation', schema=None) as batch_op:
        batch_op.drop_index('cooperation_tenant_id_idx')
        batch_op.drop_index('cooperation_created_by_idx')

    op.drop_table('cooperation')
    op.drop_table('conversation')
    with op.batch_alter_table('choice_tags', schema=None) as batch_op:
        batch_op.drop_index('choice_tag_type_idx')
        batch_op.drop_index('choice_tag_name_idx')

    op.drop_table('choice_tags')
    with op.batch_alter_table('app_versions', schema=None) as batch_op:
        batch_op.drop_index('appversions_app_id_idx')

    op.drop_table('app_versions')
    with op.batch_alter_table('app_templates', schema=None) as batch_op:
        batch_op.drop_index('app_template_id_idx')

    op.drop_table('app_templates')
    with op.batch_alter_table('app_statistics', schema=None) as batch_op:
        batch_op.drop_index(batch_op.f('app_statistics_stat_date_idx'))
        batch_op.drop_index(batch_op.f('app_statistics_app_id_idx'))

    op.drop_table('app_statistics')
    op.drop_table('api_key')
    with op.batch_alter_table('accounts', schema=None) as batch_op:
        batch_op.drop_index('account_phone_idx')
        batch_op.drop_index('account_name_idx')
        batch_op.drop_index('account_email_idx')

    op.drop_table('accounts')
    op.drop_table('account_integrates')
    # ### end Alembic commands ###


# =============================================================================
# 迁移操作示例和参考
# =============================================================================

"""
常用迁移操作示例：

1. 创建表：
   op.create_table(
       'account',
       sa.Column('id', sa.String(36), primary_key=True),
       sa.Column('name', sa.String(255), nullable=False),
       sa.Column('email', sa.String(255), nullable=False, unique=True),
       sa.Column('created_at', sa.DateTime(), nullable=False),
   )

2. 删除表：
   op.drop_table('account')

3. 添加列：
   op.add_column('account', sa.Column('phone', sa.String(20), nullable=True))

4. 删除列：
   op.drop_column('account', 'phone')

5. 修改列：
   op.alter_column('account', 'name', type_=sa.String(500))

6. 创建索引：
   op.create_index('idx_account_email', 'account', ['email'])

7. 删除索引：
   op.drop_index('idx_account_email', 'account')

8. 创建外键：
   op.create_foreign_key(
       'fk_user_account_id', 'user', 'account',
       ['account_id'], ['id']
   )

9. 删除外键：
   op.drop_constraint('fk_user_account_id', 'user', type_='foreignkey')

10. 数据迁移：
    connection = op.get_bind()
    connection.execute(
        sa.text("UPDATE account SET status = 'active' WHERE status IS NULL")
    )
"""